#ifndef QCONNECTIONPOOL_H
#define QCONNECTIONPOOL_H

#include <QtSql>
#include <QQueue>
#include <QString>
#include <QMutex>
#include <QMutexLocker>
#include "gloablevariant.h"




class QConnectionPool
{
public:
    QConnectionPool(int nId)
    {
        m_nPoolID = nId;
        maxWaitTime = 1000;
        waitInterval = 200;
        maxConnectionCount = 20;
    }
    int getMaxWaitTime() const { return maxWaitTime; }
    void setMaxWaitTime(int value) { maxWaitTime = value; }
    int getWaitInterval() const { return waitInterval; }
    void setWaitInterval(int value) { waitInterval = value; }
    int getMaxConnectionCount() const { return maxConnectionCount; }
    void setMaxConnectionCount(int value) { maxConnectionCount = value; }

    ~QConnectionPool()
    {
        foreach(QString connectionName, usedConnectionNames)
        {
            QSqlDatabase::removeDatabase(connectionName);
        }

        foreach(QString connectionName, unusedConnectionNames)
        {
            QSqlDatabase::removeDatabase(connectionName);
        }
    }

    void release()
    {
        delete this;
    }

    void setSqlServerPara(QString strUserName, QString strPassword, QString strHostName, int nPort, QString strDatabaseName)
    {
        m_strHostName = strHostName;
        m_strUsername = strUserName;
        m_strPassword = strPassword;
        m_nPort = nPort;
        m_strDatabaseType = "QODBC";
        m_strDatabaseName = strDatabaseName;
        m_eDbType = DB_SQLSERVER;
    }
    void setMysqlPara(QString strUserName, QString strPassword, QString strHostName, int nPort, QString strDatabaseName)
    {
        m_strHostName = strHostName;
        m_strUsername = strUserName;
        m_strPassword = strPassword;
        m_nPort = nPort;
        m_strDatabaseType = "QMYSQL";
        m_strDatabaseName = strDatabaseName;
        m_eDbType = DB_MYSQL;
    }
    void setSQlitePara(QString strDatabaseName)
    {
        m_strDatabaseName = strDatabaseName;
        m_strDatabaseType = "QSQLITE";
        m_eDbType = DB_SQLITE;
    }

    DB_TYPE GetDBType()
    {
        return m_eDbType;
    }

    QSqlDatabase openConnection()
    {
        QString connectionName;
        QMutexLocker locker(&mutex);

        // 已创建连接数
        int connectionCount = unusedConnectionNames.size() + usedConnectionNames.size();

        // 如果连接已经用完，等待 waitInterval 毫秒看看是否有可用连接，最长等待 maxWaitTime 毫秒
        for (int i = 0; i < maxWaitTime && unusedConnectionNames.size() == 0 && connectionCount == maxConnectionCount; i += waitInterval)
        {
            waitConnection.wait(&mutex, waitInterval);

            // 重新计算已创建连接数
            connectionCount = unusedConnectionNames.size() + usedConnectionNames.size();
        }

        if (unusedConnectionNames.size() > 0)
        {
            // 有已经回收的连接，复用它们
            connectionName = unusedConnectionNames.dequeue();
        }
        else if (connectionCount < maxConnectionCount)
        {
            // 没有已经回收的连接，但是没有达到最大连接数，则创建新的连接
            connectionName = QString("Connection-%1-%2").arg(m_nPoolID).arg(connectionCount + 1);
        }
        else
        {
            // 已经达到最大连接数
            qDebug() << "Cannot create more connections.";
            return QSqlDatabase();
        }

        // 创建连接
        QSqlDatabase db = createConnection(connectionName);

        // 有效的连接才放入 usedConnectionNames
        if (db.isOpen())
        {
            usedConnectionNames.enqueue(connectionName);
        }

        return db;
    }

    void closeConnection(QSqlDatabase connection)
    {
        QString connectionName = connection.connectionName();

        // 如果是我们创建的连接，从 used 里删除，放入 unused 里
        if (usedConnectionNames.contains(connectionName))
        {
            QMutexLocker locker(&mutex);
            usedConnectionNames.removeOne(connectionName);
            unusedConnectionNames.enqueue(connectionName);
            waitConnection.wakeOne();
        }
    }

private:
    QSqlDatabase createConnection(const QString &connectionName)
    {
        // 连接已经创建过了，复用它，而不是重新创建
        if (QSqlDatabase::contains(connectionName))
        {
            QSqlDatabase db1 = QSqlDatabase::database(connectionName);

            if (testOnBorrow)
            {
                // 返回连接前访问数据库，如果连接断开，重新建立连接
                QSqlQuery query(testOnBorrowSql, db1);

                if (query.lastError().type() != QSqlError::NoError && !db1.open())
                {
                    qDebug() << "Open datatabase error:" << db1.lastError().text();
                    return QSqlDatabase();
                }
            }

            return db1;
        }

        // 创建一个新的连接
        QSqlDatabase db = QSqlDatabase::addDatabase(m_strDatabaseType, connectionName);

        if (m_strDatabaseType.compare("QSQLITE", Qt::CaseInsensitive) == 0)
        {
            db.setDatabaseName(m_strDatabaseName);
        }
        else if (m_strDatabaseType.compare("QMYSQL", Qt::CaseInsensitive) == 0)
        {
            db.setHostName(m_strHostName);
            db.setDatabaseName(m_strDatabaseName);
            db.setUserName(m_strUsername);
            db.setPassword(m_strPassword);
            db.setPort(m_nPort);
        }else if(m_strDatabaseType.compare("QODBC", Qt::CaseInsensitive) == 0)
        {
            QString connectionString =
                QString("DRIVER={ODBC Driver 17 for SQL Server};" // 驱动名称（需安装）
                        "SERVER=%1;"               // 服务器地址
                        "DATABASE=%2;"             // 数据库名
                        "UID=%3;"                      // 用户名
                        "PWD=%4;"                      // 密码
                        "Trusted_Connection=no;").arg(m_strHostName)
                    .arg(m_strDatabaseName)
                    .arg(m_strUsername)
                    .arg(m_strPassword);                // 是否使用Windows身份验证
            db.setDatabaseName(connectionString);

        }

        if (!db.open())
        {
            qDebug() << "Open datatabase error:" << db.lastError().text();
            return QSqlDatabase();
        }

        return db;
    }

    QQueue<QString> usedConnectionNames;   // 已使用的数据库连接名
    QQueue<QString> unusedConnectionNames; // 未使用的数据库连接名

    //数据库信息
    QString m_strHostName;
    QString m_strDatabaseName;
    QString m_strUsername;
    QString m_strPassword;
    QString m_strDatabaseType;
    int m_nPort;
    bool    testOnBorrow;    // 取得连接的时候验证连接是否有效
    QString testOnBorrowSql; // 测试访问数据库的 SQL

    int maxWaitTime;  // 获取连接最大等待时间
    int waitInterval; // 尝试获取连接时等待间隔时间，做一个set和get的方法
    int maxConnectionCount; //最大连接数

    QMutex mutex;
    QWaitCondition waitConnection;
    int m_nPoolID;
    DB_TYPE m_eDbType;
};


#endif // QCONNECTIONPOOL_H
